
"""Label map utility functions."""
"""标签映射实用程序功能。"""

import logging
import tensorflow as tf
from google.protobuf import text_format
from protos import string_int_label_map_pb2
def _validate_label_map(label_map):
  """
  检查标签映射是否有效。
    Args:
      label_map: 要验证的 StringIntLabelMap。
    Raises:
      ValueError: 如果标签映射无效。
    """
  for item in label_map.item:
    if item.id < 1:
      raise ValueError('Label map ids should be >= 1.')
def create_category_index(categories):
  """创建 COCO 兼容的类别字典，以类别ID为键。
    Args:
      categories: 包含类别信息的字典列表，每个字典包含以下键：
        'id': (必需) 整数ID，唯一标识该类别。
        'name': (必需) 字符串，表示类别名称，例如 '猫'、'狗'、'披萨'。

    Returns:
      category_index: 一个字典，与 categories 中的内容相同，但以每个类别的 'id' 作为键。
    """
  category_index = {}
  for cat in categories:
    category_index[cat['id']] = cat
  return category_index


def convert_label_map_to_categories(label_map,
                                    max_num_classes,
                                    use_display_name=True):
  """加载标签映射并返回适用于评估的类别列表。

    这个函数加载标签映射并返回一个字典列表，每个字典包含以下键：
      'id': (必需) 整数ID，唯一标识该类别。
      'name': (必需) 字符串，表示类别名称，例如 '猫'、'狗'、'披萨'。
    只有当类别的 id 在 0（含）到 max_num_classes（不含）之间时，才将该类别添加到列表中。
    如果标签映射中有多个项目映射到相同的 id，则只保留列表中的第一个项目。

    Args:
      label_map: 一个 StringIntLabelMapProto 或 None。如果为 None，则创建一个包含 max_num_classes 个类别的默认列表。
      max_num_classes: 要包含的（连续的）标签索引的最大数量。
      use_display_name: (布尔值) 选择是否使用 'display_name' 字段作为类别名称。如果为 False，或者 'display_name' 字段不存在，则使用 'name' 字段作为类别名称。

    Returns:
      categories: 包含所有可能类别信息的字典列表。
    """
  categories = []
  list_of_ids_already_added = []
  if not label_map:
    label_id_offset = 1
    for class_id in range(max_num_classes):
      categories.append({
          'id': class_id + label_id_offset,
          'name': 'category_{}'.format(class_id + label_id_offset)
      })
    return categories
  for item in label_map.item:
    if not 0 < item.id <= max_num_classes:
      logging.info('Ignore item %d since it falls outside of requested '
                   'label range.', item.id)
      continue
    if use_display_name and item.HasField('display_name'):
      name = item.display_name
    else:
      name = item.name
    if item.id not in list_of_ids_already_added:
      list_of_ids_already_added.append(item.id)
      categories.append({'id': item.id, 'name': name})
  return categories


def load_labelmap(path):
  """加载标签映射协议。
   Args:
     path: StringIntLabelMap proto 文本文件的路径。

   Returns:
     一个 StringIntLabelMapProto。
   """
  with tf.io.gfile.GFile(path, 'r') as fid:
    label_map_string = fid.read()
    label_map = string_int_label_map_pb2.StringIntLabelMap()
    try:
      text_format.Merge(label_map_string, label_map)
    except text_format.ParseError:
      label_map.ParseFromString(label_map_string)
  _validate_label_map(label_map)
  return label_map


def get_label_map_dict(label_map_path):
  """读取标签映射并返回标签名称到ID的字典。

    Args:
      label_map_path: 标签映射的路径。

    Returns:
      一个字典，将标签名称映射到对应的标签ID。
    """
  label_map = load_labelmap(label_map_path)
  label_map_dict = {}
  for item in label_map.item:
    label_map_dict[item.name] = item.id
  return label_map_dict


"""
这段代码是来自 utils 目录下的 label_map_util.py 文件，它包含了一些用于处理标签映射的函数。让我们逐个函数分析并注释其功能：
_validate_label_map(label_map)：
功能：验证标签映射是否有效。
参数：label_map 是要验证的 StringIntLabelMap 对象。
抛出异常：如果标签映射无效，则抛出 ValueError 异常。
create_category_index(categories)：
功能：创建一个字典，将 COCO 兼容的类别以类别ID作为键存储。
参数：
categories：包含类别信息的列表，每个类别信息是一个字典，包含 'id' 和 'name' 键。
返回：一个字典，将类别ID映射到对应的类别信息。

convert_label_map_to_categories(label_map, max_num_classes, use_display_name=True)：
功能：将标签映射转换为适用于评估的类别列表。
参数：
label_map：StringIntLabelMap 对象，标签映射的定义。
max_num_classes：最大类别数量。
use_display_name：一个布尔值，选择是否使用显示名称作为类别名称。
返回：一个列表，包含所有可能的类别信息，每个类别信息是一个字典，包含 'id' 和 'name' 键。

load_labelmap(path)：
功能：加载标签映射文件。
参数：path 是标签映射文件的路径。
返回：一个 StringIntLabelMap 对象，表示加载的标签映射。

get_label_map_dict(label_map_path)：
功能：读取标签映射并返回标签名称到ID的字典。
参数：label_map_path 是标签映射文件的路径。
返回：一个字典，将标签名称映射到对应的标签ID。
这些函数主要用于加载、验证和处理标签映射信息，方便在人脸识别项目中使用。

"""